home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / timeout.c < prev    next >
C/C++ Source or Header  |  1993-08-16  |  5KB  |  233 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8.  
  9. /*
  10.  * We initialize proc_clock to a very large value so that we don't have
  11.  * to worry about unexpected process switches while starting up
  12.  */
  13.  
  14. short proc_clock = 0x7fff;
  15.  
  16. /* used by filesystems for time/date stamps; updated once per second */
  17. short timestamp, datestamp;
  18.  
  19. extern short in_kernel;    /* in main.c */
  20.  
  21. static void unnapme P_((PROC *));
  22.  
  23. /*
  24.  * addtimeout(long delta, void (*func)()): schedule a timeout for the current
  25.  * process, to take place in "delta" milliseconds. "func" specifies a
  26.  * function to be called at that time; the function is passed as a parameter
  27.  * the process for which the timeout was specified (i.e. the value of
  28.  * curproc at the time addtimeout() was called; note that this is probably
  29.  * *not* the current process when the timeout occurs).
  30.  */
  31.  
  32. TIMEOUT *tlist;
  33.  
  34. #define newtimeout() (TIMEOUT *)kmalloc(SIZEOF(TIMEOUT))
  35. #define disposetimeout(t) kfree(t)
  36.  
  37. TIMEOUT * ARGS_ON_STACK
  38. addtimeout(delta, func)
  39.     long delta;
  40.     void (*func) P_((PROC *));
  41. {
  42.     TIMEOUT *t, **prev, *cur;
  43.  
  44.     t = newtimeout();
  45.  
  46. /* BUG: we should have some fallback mechanism for timeouts when the
  47.    kernel memory is exhausted
  48.  */
  49.     assert(t);
  50.  
  51.     t->proc = curproc;
  52.     t->func = func;
  53.  
  54.     cur = tlist;
  55.     prev = &tlist;
  56.     while (cur) {
  57.         if (cur->when >= delta) {
  58.             cur->when -= delta;
  59.             t->next = cur;
  60.             t->when = delta;
  61.             *prev = t;
  62.             return t;
  63.         }
  64.         delta -= cur->when;
  65.         prev = &cur->next;
  66.         cur = cur->next;
  67.     }
  68.     assert(delta >= 0);
  69.     t->when = delta;
  70.     t->next = cur;
  71.     *prev = t;
  72.     return t;
  73. }
  74.  
  75. /*
  76.  * cancelalltimeouts(): cancels all pending timeouts for the current
  77.  * process
  78.  */
  79.  
  80. void ARGS_ON_STACK
  81. cancelalltimeouts()
  82. {
  83.     TIMEOUT *cur, **prev, *old;
  84.     long delta;
  85.  
  86.     cur = tlist;
  87.     prev = &tlist;
  88.     while (cur) {
  89.         if (cur->proc == curproc) {
  90.             delta = cur->when;
  91.             old = cur;
  92.             *prev = cur = cur->next;
  93.             if (cur) cur->when += delta;
  94.             disposetimeout(old);
  95.         }
  96.         else {
  97.             prev = &cur->next;
  98.             cur = cur->next;
  99.         }
  100.     }
  101. }
  102.  
  103. /*
  104.  * Cancel a specific timeout. If the timeout isn't on the list, or isn't
  105.  * for this process, we do nothing; otherwise, we cancel the time out
  106.  * and then free the memory it used. *NOTE*: it's very possible (indeed
  107.  * likely) that "this" was already removed from the list and disposed of
  108.  * by the timeout processing routines, so it's important that we check
  109.  * for it's presence in the list and do absolutely nothing if we don't
  110.  * find it there!
  111.  */
  112.  
  113. void ARGS_ON_STACK
  114. canceltimeout(this)
  115.     TIMEOUT *this;
  116. {
  117.     TIMEOUT *cur, **prev;
  118.  
  119.     prev = &tlist;
  120.     for (cur = tlist; cur; cur = cur->next) {
  121.         if (cur == this && cur->proc == curproc) {
  122.             *prev = cur->next;
  123.             if (cur->next) {
  124.                 cur->next->when += this->when;
  125.             }
  126.             disposetimeout(this);
  127.             break;
  128.         }
  129.         prev = &cur->next;
  130.     }
  131. }
  132.  
  133. /*
  134.  * timeout: called every 20 ms or so by GEMDOS, this routine
  135.  * is responsible for maintaining process times and such.
  136.  * it should also decrement the "proc_clock" variable, but
  137.  * should *not* take any action when it reaches 0 (the state of the
  138.  * stack is too uncertain, and time is too critical). Instead,
  139.  * a vbl routine checks periodically and if "proc_clock" is 0
  140.  * suspends the current process
  141.  */
  142.  
  143. volatile int our_clock = 1000;
  144.  
  145. void ARGS_ON_STACK
  146. timeout()
  147. {
  148.     int ms;        /* time between ticks */
  149.  
  150.     ms = *((short *)0x442L);
  151.     if (proc_clock > 0)
  152.         proc_clock--;
  153.  
  154.     our_clock -= ms;
  155.     if (tlist) {
  156.         tlist->when -= ms;
  157.     }
  158. }
  159.  
  160. /*
  161.  * sleep() calls this routine to check on alarms and other sorts
  162.  * of time-outs on every context switch.
  163.  */
  164.  
  165. void
  166. checkalarms()
  167. {
  168.     extern long searchtime;        /* in dosdir.c */
  169.     PROC *p;
  170.     long delta;
  171.     void (*evnt) P_((PROC *));
  172.     TIMEOUT *old;
  173.  
  174. /* do the once per second things */
  175.     while (our_clock < 0) {
  176.         our_clock += 1000;
  177.         timestamp = Tgettime();
  178.         datestamp = Tgetdate();
  179.         searchtime++;
  180.         reset_priorities();
  181.     }
  182.  
  183. /* see if there are outstanding timeout requests to do */
  184.     while (tlist && ((delta = tlist->when) <= 0)) {
  185.         p = tlist->proc;
  186.         TRACE(("doing timeout code for pid %d", p->pid));
  187.         evnt = tlist->func;
  188.         old = tlist;
  189.         tlist = tlist->next;
  190.         disposetimeout(old);
  191.     /* call the timeout function */
  192.         (*evnt)(p);
  193.  
  194. /* if delta < 0, it's possible that the time has come for the next timeout
  195.    to occur */
  196.         if (tlist)
  197.             tlist->when += delta;
  198.     }
  199. }
  200.  
  201. /*
  202.  * nap(n): nap for n milliseconds. Used in loops where we're waiting for
  203.  * an event. If we expect the event *very* soon, we should use yield
  204.  * instead.
  205.  * NOTE: we may not sleep for exactly n milliseconds; signals can wake
  206.  * us earlier, and the vagaries of process scheduling may cause us to
  207.  * oversleep...
  208.  */
  209.  
  210. static void
  211. unnapme(p)
  212.     PROC *p;
  213. {
  214.     if (p->wait_q == SELECT_Q && p->wait_cond == (long)nap) {
  215.         short sr = spl7();
  216.         rm_q(SELECT_Q, p);
  217.         add_q(READY_Q, p);
  218.         spl(sr);
  219.         p->wait_cond = 0;
  220.     }
  221. }
  222.  
  223. void ARGS_ON_STACK 
  224. nap(n)
  225.     unsigned n;
  226. {
  227.     TIMEOUT *t;
  228.  
  229.     t = addtimeout((long)n, unnapme);
  230.     sleep(SELECT_Q, (long)nap);
  231.     canceltimeout(t);
  232. }
  233.